#include "game.h"

#include "bt.h"
#include "flash.h"
#include "kb.h"
#include "oled.h"
#include "tetris.h"
#include "ws2812.h"

#undef Handler
#define Handler Game_HandleTypeDef*

#undef handler
#define handler (**(Game_HandleTypeDef**)&handle)

const uint32_t Game_addr = FLASH_PAGE_95;

void Game_Init(void* handle) {
  uint16_t** tmp = (uint16_t**)(&Game_addr);
  uint16_t* ptr = (uint16_t*)handle;
  for (uint16_t i = 0; i < 512; i++) {
    ptr[i] = (*tmp)[i];
  }
  handler.into = 0;
  handler.outo = 0;
  handler.mode = 0;
  handler.mode = GAME_BEGIN;
  Game_Reinit(handle);
}
void Game_Reinit(void* handle) {
  // 初始化bt
  Bt_Init(Game_M_L, NULL, NULL, Game_M_O,    // M
          Game_U_LJ, NULL, Game_U_LJ, NULL,  // U
          Game_D_LJ, NULL, Game_D_LJ, NULL,  // D
          Game_L_LJ, NULL, Game_L_LJ, NULL,  // L
          Game_R_LJ, NULL, Game_R_LJ, NULL,  // R
          200);
  Ws_Init();
  handler.into = 0;
  Game_InitShow(handle);
  turn = 0xFF;
  Game_ShowLine(handle);
  turn = 0x00;
  // 死循环, 直到所有按键松开
  while (hbt.bu & BU_M) Bt_Update();
}
void Game_InitShow(void* handle) {
  Oled_ClearAll();
  turn = 0xFF;
  Oled_ShowStringBig(0, 0, "      Game      ");
  turn = 0x00;
  Oled_ShowStringSmall(0, 2, "Start[M]");
  Oled_ShowStringSmall(0, 3, "Rank[M]");
  Oled_ShowStringSmall(0, 4, "Speed[L/R]");
  Oled_ShowNumSmall(116, 4, handler.speed, 2);
  Oled_ShowStringSmall(0, 5, "User[M]:");
  Oled_ShowStringSmall(128 - handler.len * 6, 5, (char*)handler.user);
}
void Game_ShowLine(void* handle) {
  switch (handler.mode) {
    case GAME_START:
      Oled_ShowStringSmall(0, 2, "Start[M]");
      break;
    case GAME_RANK:
      Oled_ShowStringSmall(0, 3, "Rank[M]");
      break;
    case GAME_SPEED:
      Oled_ShowStringSmall(0, 4, "Speed[L/R]:");
      Oled_ShowNumSmall(116, 4, handler.speed, 2);
      break;
    case GAME_USER:
      Oled_ShowStringSmall(0, 5, "User[M]:");
      Oled_ShowStringSmall(128 - handler.len * 6, 5, (char*)handler.user);
      break;
    default:
      break;
  }
}

void Game_Run(void* handle) {
  while (1) {
    Bt_Update();
    Bt_Run(handle);
    // 判断是否进入子页面
    if (handler.into) {
      switch (handler.mode) {
        case GAME_START: {
          Tetris_HandleTypeDef htetris;
          Tetris_Init(&htetris, handler.speed);
          Tetris_Run(&htetris);
          for (uint8_t i = 0; i < 3; i++) {
            if (htetris.score >= handler.rank[i].score) {
              // 将后面的排名依次往后移动一位
              for (uint8_t j = 2; j > i; j--) {
                // 移动分数
                handler.rank[j].score = handler.rank[j - 1].score;
                // 移动名字
                for (uint8_t k = 0; k < 16; k++) {
                  handler.rank[j].name[k] = handler.rank[j - 1].name[k];
                }
              }
              // 插入新排名
              handler.rank[i].score = htetris.score;
              for (uint8_t k = 0; k < 16; k++) {
                handler.rank[i].name[k] = handler.user[k];
              }
              break;
            }
          }
        } break;
        case GAME_RANK: {
          Oled_ClearAll();
          turn = 0xFF;
          Oled_ShowStringBig(0, 0, "      RANK      ");
          turn = 0x00;
          Oled_ShowStringSmall(0, 2, "1.");
          Oled_ShowStringSmall(0, 3, "2.");
          Oled_ShowStringSmall(0, 4, "3.");
          Oled_ShowStringSmall(12, 2, (char*)handler.rank[0].name);
          Oled_ShowStringSmall(12, 3, (char*)handler.rank[1].name);
          Oled_ShowStringSmall(12, 4, (char*)handler.rank[2].name);
          Oled_ShowNumSmall(104, 2, handler.rank[0].score, 4);
          Oled_ShowNumSmall(104, 3, handler.rank[1].score, 4);
          Oled_ShowNumSmall(104, 4, handler.rank[2].score, 4);
          while (hbt.bu & BU_M) Bt_Update();
          HAL_Delay(10);  // 防止抖动
          while (!(hbt.bu & BU_M_M)) Bt_Update();
        } break;
        case GAME_SPEED: {
        } break;
        case GAME_USER: {
          Kb_HandleTypeDef hkb;
          Kb_Init(&hkb, (char*)handler.user);
          Kb_Run(&hkb);
          if (hkb.save) {
            uint8_t k = 0;
            while (hkb.str[k] != '\0' && k < 13) {
              handler.user[k] = hkb.str[k];
              k++;
            }
            handler.len = k < 13 ? k : 12;
            handler.user[handler.len] = '\0';
          }
        }
      }
      Game_Reinit(handle);
    }
    // 判断是否退出当前页面
    if (handler.outo) {
      // 保存数据
      Flash_Erase(Game_addr);
      Flash_Write(Game_addr, handle, 512);
      return;
    }
  }
}

void Game_M_L(void* handle) { handler.outo = 1; }
// M键的点击任务只能被当最O型执行, 否则会覆盖M键的长按任务,
// 因为M键点击之后就进入子页面了, 跳转到子页面的Run函数,
// 而此页面的长按任务自然无法执行
void Game_M_O(void* handle) {
  if (handler.mode != GAME_SPEED) handler.into = 1;
}
// 此处把U键的任务实现为LWO型, 是为了与M键保持统一的用户体验,
// 另一种方式是将其实现为J型, 这样代码能简单一点点
void Game_U_LJ(void* handle) {
  Game_ShowLine(handle);
  if (handler.mode > GAME_BEGIN) {
    handler.mode--;
  } else {
    handler.mode = GAME_END;
  }
  turn = 0xFF;
  Game_ShowLine(handle);
  turn = 0x00;
}
void Game_D_LJ(void* handle) {
  // if (!(hbt.bu & BU_S_D) && hbt.hist) return;
  Game_ShowLine(handle);
  if (handler.mode < GAME_END) {
    handler.mode++;
  } else {
    handler.mode = GAME_BEGIN;
  }
  turn = 0xFF;
  Game_ShowLine(handle);
  turn = 0x00;
}
void Game_L_LJ(void* handle) {
  if (handler.mode == GAME_SPEED) {
    if (handler.speed >= 1) {
      handler.speed--;
      turn = 0xFF;
      Oled_ShowNumSmall(116, 4, handler.speed, 2);
      turn = 0x00;
    }
  }
}
void Game_R_LJ(void* handle) {
  if (handler.mode == GAME_SPEED) {
    if (handler.speed < 7) {
      handler.speed++;
      turn = 0xFF;
      Oled_ShowNumSmall(116, 4, handler.speed, 2);
      turn = 0x00;
    }
  }
}
